/*=====================================================================================
* Copyright (c) 2020, micROS Group, NIIDT, TAIIC.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
*  provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and
*      the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
*      and the following disclaimer in the documentation and/or other materials provided with the
*      distribution.
* 3. All advertising materials mentioning features or use of this software must display the following
*      acknowledgement: This product includes software developed by the micROS Group and its
*      contributors.
* 4. Neither the name of the Group nor the names of contributors may be used to endorse or promote
*     products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY MICROS GROUP AND CONTRIBUTORS ''AS IS''AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR  PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE MICROS, GROUP OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
*  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
*  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION). HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=====================================================================================
* Author: Longfei Su, Tianhao Zhang.
*/
#ifndef __YOLOV3_GPU_DETECTOR_H
#define __YOLOV3_GPU_DETECTOR_H

#if (__cplusplus == 201103L)
#include <unordered_map>
#include <unordered_set>
#else
#include <tr1/unordered_map>
#include <tr1/unordered_set>
#endif

#include <opencv2/dnn.hpp>
#include <cognition_resource/optical_detection.resource.h>

namespace optical_detector
{
  class yoloV3GPUDetector : public cognition::OpticalDetection::Resource
  {
  public:
    yoloV3GPUDetector();
    ~yoloV3GPUDetector() override;
    virtual bool Initialize(const std::string& resource_id) override;

    virtual void setParams(float aConfidenceThres,                           // Confidence threshold
                            std::unordered_set<std::string> aTargetClassname, // Classes need to be detected
                            std::string aModelFilePath,                       // Model file path
                            size_t aWidth,                                    // Block width to DNN
                            size_t aHeight) override;


    virtual bool inference(cv::Mat &pFrame,
                      std::vector<cv::Rect2d> &pRoi,
                      std::vector<std::string> &pName,
                      std::vector<float> &pConf) override;

    int cnt;
    double time_sum;
    double time_mean;
    float _confidenceThreshold=0.01;

  private:
    void drawPred(int aClassId, float aConf, int aLeft, int aTop, int aRight, int aBottom, cv::Mat &pFrame);
    std::vector<cv::String> getOutputsNames(const cv::dnn::Net &pNet);

    std::unordered_set<std::string> _targetName;
    cv::dnn::Net _dnnNet;
    std::vector<std::string> _classNames;
    std::string model_id_;
    size_t _inWidth, _inHeight;
    float _inScaleFactor, _meanVal;
    const std::string _kWinName = "YoloV3 object detection";
  };

  void cakkbacktiny(int, void *userdata);
  int *runofftiny(cv::Mat &pFrame,
                  float _confidenceThreshold,
                  const std::vector<cv::Mat> &pOut,
                  cv::dnn::Net &pNet,
                  std::vector<cv::Rect2d> &pRoi,
                  std::vector<std::string> &pName,
                  std::vector<float> &pConf,
                  bool &pDetected);
} // namespace optical_detector

#endif
